package org.jeecg.modules.flowable.service.impl;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.Activity;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.SequenceFlow;
import org.flowable.bpmn.model.StartEvent;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.flowable.dto.FlowTaskOperationDTO;
import org.jeecg.modules.flowable.entity.FlowInstance;
import org.jeecg.modules.flowable.entity.FlowOperationInfo;
import org.jeecg.modules.flowable.enums.FlowInstanceStatusEnum;
import org.jeecg.modules.flowable.enums.TaskOperationTypeEnum;
import org.jeecg.modules.flowable.mapper.FlowTaskMapper;
import org.jeecg.modules.flowable.query.FlowTaskQuery;
import org.jeecg.modules.flowable.service.FlowInstanceService;
import org.jeecg.modules.flowable.service.FlowOperationInfoService;
import org.jeecg.modules.flowable.service.FlowTaskService;
import org.jeecg.modules.flowable.vo.FlowTaskVO;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class FlowTaskServiceImpl implements FlowTaskService {

    final TaskService taskService;

    final RuntimeService runtimeService;

    final FlowTaskMapper flowTaskMapper;

    final RepositoryService repositoryService;

    final FlowInstanceService flowInstanceService;

    final FlowOperationInfoService flowOperationInfoService;

    @Override
    public Result<Page<FlowTaskVO>> todoList(FlowTaskQuery query) {
        return Result.OK(this.flowTaskMapper.todoList(new Page<>(query.getPageIndex(), query.getPageSize()), query));
    }

    @Override
    public Result<Void> complete(FlowTaskOperationDTO operationDTO) {
        String taskId = operationDTO.getTaskId();
        // 查询事项是否存在
        TaskEntity task = (TaskEntity) this.taskService.createTaskQuery().taskId(taskId).singleResult();
        if (Objects.isNull(task)) {
            return Result.error("任务不存在，或已处理！");
        }
        // 记录流转状态
        FlowOperationInfo operationInfo = new FlowOperationInfo();
        operationInfo.setId(IdUtil.fastSimpleUUID());
        operationInfo.setTaskId(task.getId());
        operationInfo.setTaskName(task.getName());
        operationInfo.setActivityId(task.getTaskDefinitionKey());
        operationInfo.setOperatorType(TaskOperationTypeEnum.APPROVE.getCode());
        operationInfo.setProcessInstanceId(operationDTO.getProcessInstanceId());
        operationInfo.setOperationUserId(operationDTO.getUserId());
        operationInfo.setOperationUserName(operationDTO.getUserName());
        operationInfo.setOperationTime(LocalDateTime.now());
        operationInfo.setMessage(operationDTO.getMessage());
        this.flowOperationInfoService.save(operationInfo);
        // 执行流转任务
        this.taskService.complete(taskId);
        return Result.OK();
    }

    @Override
    public Result<Void> veto(FlowTaskOperationDTO operationDTO) {
        // 获取流程实例
        String processInstanceId = operationDTO.getProcessInstanceId();
        ProcessInstance processInstance = this.runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        if (Objects.isNull(processInstance)) {
            return Result.error("当前流程实例不存在，或已处理！");
        }

        String processDefinitionId = processInstance.getProcessDefinitionId();
        // 获取第一个用户任务，开始节点的下一个任务
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        List<StartEvent> startEventList = bpmnModel.getMainProcess().findFlowElementsOfType(StartEvent.class);
        StartEvent startEvent = startEventList.get(0);
        List<SequenceFlow> sequenceFlowList = startEvent.getOutgoingFlows();
        SequenceFlow sequenceFlow = sequenceFlowList.get(0);
        // 第一个用户节点
        Activity activity = (Activity) sequenceFlow.getTargetFlowElement();
        String activityId = activity.getId();


        // 获取执行记录
        List<Execution> executions = this.runtimeService.createExecutionQuery().parentId(processInstanceId).list();
        // 所有节点回退到开始节点
        this.runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(processInstanceId)
                .moveExecutionsToSingleActivityId(executions.stream().map(Execution::getId).collect(Collectors.toList()), activityId)
                .changeState();
        // 记录流转状态
        FlowOperationInfo operationInfo = new FlowOperationInfo();
        operationInfo.setOperatorType(TaskOperationTypeEnum.REVOKE.getCode());
        operationInfo.setProcessInstanceId(operationDTO.getProcessInstanceId());
        operationInfo.setOperationUserId(operationDTO.getUserId());
        operationInfo.setOperationUserName(operationDTO.getUserName());
        operationInfo.setOperationTime(LocalDateTime.now());
        operationInfo.setMessage(operationDTO.getMessage());
        this.flowOperationInfoService.save(operationInfo);

        // 更新流程状态
        this.flowInstanceService.updateInstanceStatus(processInstanceId, FlowInstanceStatusEnum.WAIT);
        return Result.OK();
    }
}
